#pragma once
#include <string>
#include <iostream>
#include <vector>
#include <sstream>
#include <string.h>
#include "Log.hpp"
#include <unordered_map>
#include <memory>
#include <fstream>
#include <functional>

static const std::string sep = "\r\n";
static const std::string homepage = "index.html";//主页
static const std::string filesuffixsep = ".";
static const std::string header_sep = ": ";
static const std::string httpversion = "HTTP/1.0";
static const std::string space = " ";
static const std::string args_sep = "?";


class HttpResponse;
class HttpRequest;

using func_t = function<std::shared_ptr<HttpResponse>(std::shared_ptr<HttpRequest>)>;

class HttpRequest
{
private:

    std::string GetOneLine(std::string& reqstr)
    {
        //判断一下是不是空串
        if(reqstr.empty())
            return reqstr;

        auto pos = reqstr.find(sep);
        if(pos == std::string::npos)
        {
            return std::string();
        }
        std::string line = reqstr.substr(0,pos);
        reqstr.erase(0,pos+sep.size());
        return line.empty()?sep:line;
    }

    //k，v输出型参数
    bool ParseHeaderHelper(const std::string &line, std::string *k, std::string *v)
    {
        auto pos = line.find(header_sep);
        if(pos==std::string::npos)
            return false;
        *k = line.substr(0,pos);
        *v = line.substr(pos+header_sep.size());
        return true;
    }

public:

     HttpRequest()
    :_blank_line(sep),_path("wwwroot")
    {}


    void Print()
    {
        std::cout << "===" << _req_line << std::endl;
        for (auto &header : _req_header)
        {
            std::cout << "***" << header << std::endl;
        }
        std::cout << _blank_line;
        std::cout << _req_text << std::endl;

        std::cout << "method ### " << _method << std::endl;
        std::cout << "url ### " << _url << std::endl;
        std::cout << "path ### " << _path << std::endl;
        std::cout << "httpverion ### " << _version << std::endl;
        for (auto &header : _headers)
        {
            std::cout << "@@@" << header.first << " - " << header.second << std::endl;
        }
    }

    bool ParseReqLine()
    {
        //解析请求行参数
        if(_req_line.empty())
            return false;
        std::stringstream ss(_req_line);
        //以空格为分隔符
        ss>>_method>>_url>>_version;

        //如果请求方法是get，可能会带参数
        if(strcasecmp("get",_method.c_str())==0)
        {
            auto pos = _url.find(args_sep);
            if(pos!=std::string::npos)
            {
                Log(INFO, "change begin, url: %s\n", _url.c_str());
                _args = _url.substr(pos+args_sep.size());
                _url.resize(pos);
                Log(INFO, "change done, url: %s, _args: %s\n", _url.c_str(), _args.c_str());
            }
        }

        _path  += _url;
        Log(DEBUG, "url: %s\n", _url.c_str());

        //如果请求的是wwwroot/ ---> wwwroot/index.html
        if(_path[_path.size()-1]=='/')
        {
            _path += homepage;
        }
        //通过文件后缀判断传输类型
        auto pos = _path.rfind(filesuffixsep);
        if(pos==std::string::npos)
        {
            _suffix = ".unkown";//未知文件后缀
        }
        else
        {
            _suffix = _path.substr(pos);
        }

        Log(INFO, "client wang get %s, _suffix: %s\n", _path.c_str(), _suffix.c_str());
        return true;

    }

    bool ParseHeader()
    {
        for(auto& header : _req_header)
        {
            std::string k,v;
            if(ParseHeaderHelper(header,&k,&v))
            {
                _headers.insert(std::make_pair(k,v));
            }
        }
        return true;
    }

    void Derialize(std::string reqstr)
    {
        _req_line = GetOneLine(reqstr);//读取一行并删除
        while(1)
        {
            //一直读取直到读取到空行
            string line = GetOneLine(reqstr);
            if(line.empty())
                break;
            else if(line==sep)
            {
                //line读取到的是空行，下一行就是正文
                _req_text = reqstr;
                break;
            }
            else
            {
                _req_header.emplace_back(line);
            }
        }

        ParseReqLine();
        ParseHeader();
    }

    bool IsExec()
    {
        return !_args.empty()||!_req_text.empty();//说明请求带参数
    }

    std::string Path()
    {
        return _path;
    }

    std::string Suffix()
    {
        return _suffix;
    }

    std::string Method()
    {
        return _method;
    }

    std::string Args()
    {
        return _args;
    }

    std::string Text()
    {
        return _req_text;
    }

private:
    std::string _req_line;//请求行
    std::vector<std::string> _req_header;//报头
    std::string _blank_line;
    std::string _req_text;//正文

    std::string _method;//请求方法
    std::string _url;
    std::string _version;//版本
    std::string _path;//默认路径 + 请求资源路径
    std::string _suffix;//文件后缀
    std::string _args;//参数
    unordered_map<std::string,std::string> _headers;

};


class HttpResponse
{
public:
    HttpResponse()
    :_version(httpversion),_blank_line(sep)
    {}

    void AddStatusLine(int code, const std::string &desc)
    {
        _code = code;
        _desc = desc;
    }

    void AddHeader(const std::string &k, const std::string &v)
    {
        Log(DEBUG, "AddHeader: %s->%s\n", k.c_str(), v.c_str());
        _headers[k] = v;
    }

    void AddText(const std::string &text)
    {
        _resp_text = text;
    }

    std::string Serialize()
    {
        //直接返回序列化好的子串 
        _status_line = _version + space + std::to_string(_code) + space + _desc + sep;
        for(auto& header : _headers)
        {
            _resp_headers.emplace_back(header.first + header_sep +header.second + sep);
        }

        //序列化
        std::string respstr = _status_line;
        for(auto& header : _resp_headers)
        {
            respstr += header;
        }
        respstr += _blank_line;
        respstr += _resp_text;
        
        return respstr;
    }

private:
    std::string _version;
    int _code;
    std::string _desc;//状态码表述
    std::unordered_map<std::string,std::string> _headers;//报头数据

    std::string _status_line;//状态行
    std::vector<std::string> _resp_headers;
    std::string _blank_line;
    std::string _resp_text;

};



class Factory
{
public:
    static std::shared_ptr<HttpRequest> BuildHttpRequest()
    {
        return std::make_shared<HttpRequest>();
    }
    static std::shared_ptr<HttpResponse> BuildHttpResponse()
    {
        return std::make_shared<HttpResponse>();
    }
};


class HttpServer
{


    public:
    
    HttpServer()
    {
        //添加对应的类型映射
        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".css", "text/css"));
        _mime_type.insert(std::make_pair(".js", "application/x-javascript"));
        _mime_type.insert(std::make_pair(".png", "image/png"));
        _mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mime_type.insert(std::make_pair(".unknown", "text/html")); 

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
        _code_to_desc.insert(std::make_pair(500, "Internal Server Error"));
    }

    std::string ReadFileContent(const std::string&path,int* size)
    {
        //size输出型参数
        std::ifstream in(path,std::ios::binary);//以二进制形式打开path文件
        if(!in.is_open())
        {
            return std::string();
        }
        in.seekg(0,in.end);
        int filesize = in.tellg();
        in.seekg(0,in.beg);

        std::string content;
        //content.reserve不可以使用
        content.resize(filesize);
        in.read((char*)content.c_str(),filesize);
        in.close();
        *size = filesize;
        return content;
        
    }

    void AddHandler(std::string path,func_t func)
    {
        _funcs.insert(std::make_pair("wwwroot"+path,func));
    }


    std::string HandlerHttpRequest(std::string request)
    {
#ifdef Test
        std::cout<<"-------------------------"<<std::endl;
        std::cout<<request;

        //报头
        std::string response = "HTTP/1.0 200 ok\r\n";
        //空行
        response += "\r\n";
        //有效载荷
        response += "<html><body><head>hello world</head></body></html>";
        
        return response;
#else
        std::cout << "---------------------------------------" << std::endl;
        std::cout << request;
        auto req = Factory::BuildHttpRequest();
        req->Derialize(request);


        if(req->IsExec())
        {
            auto resp = _funcs[req->Path()](req);
            return resp->Serialize();//返回一个序列化的字符串
            
        }
        else
        {
            int code = 200;
            int contentsize = 0;
            auto resp = Factory::BuildHttpResponse();
            std::string text = ReadFileContent(req->Path(),&contentsize);
            if(text.empty())
            {
                code = 404;
                resp->AddStatusLine(code,_code_to_desc[code]);
                std::string text404 = ReadFileContent("wwwroot/404.html",&contentsize);//把404.html中的内容读取出来，放到正文中
                resp->AddHeader("Content-Length",std::to_string(contentsize));
                resp->AddHeader("Content-Type",_mime_type[".html"]);
                resp->AddText(text404);
            }
            else
            {
                std::string suffix = req->Suffix();
                resp->AddStatusLine(code,_code_to_desc[code]);
                resp->AddHeader("Content-Length",std::to_string(contentsize));
                resp->AddHeader("Content-Type",_mime_type[suffix]);
                resp->AddText(text);    
            }

            return resp->Serialize();
        }


       
#endif
    }


    private:
        std::unordered_map<std::string,std::string> _mime_type;
        std::unordered_map<int,std::string> _code_to_desc;
        std::unordered_map<std::string,func_t> _funcs;
};